﻿#region Header

/*
Behavioral Rating of Dancing Human Crowds based on Motion Patterns
By

Pascal Hauser 
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

and

Raphael Gfeller
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

*/

#endregion

#region Usings

using System;
using System.Drawing;
using System.Threading;
using Emgu.CV;
using Emgu.CV.Structure;
using paravili.Services;
using Sebarf.Services.Interfaces;

#endregion

namespace paravili.Steps {
	/// <summary>
	/// Gets a new image of the given <see cref="ICaptureSource"/>
	/// </summary>
	public class NextImageProvider : ProcessStepConverterWithMeasurement<ICaptureSource, Image<Bgr, Byte>> {
		#region Public Properties

		[ConfigurabelStringValue(Name = "ImageProviderId")]
		public String ImageProviderId { get; set; }

		[ConfigurabelBooleanValue(Name = "ForwardImageToImageProvider")]
		public bool ForwardImageToImageProvider { get; set; }

		[ServiceRequest(IsOptional = true)]
		public IImageProviderService ImageProviderService { get; set; }

		[ServiceRequest(IsOptional = true)]
		public ICurrentCaptureSourceInformationProviderService CurrentCaptureSourceInformationProviderService { get; set; }

		[ServiceRequest(IsOptional = true)]
		public IImageValidRegionProvider ImageValidRegionProvider { get; set; }

		[ServiceRequest]
		public ICurrentImageInformationProviderService CurrentImageInformationProviderService { get; set; }

		[ConfigurabelBooleanValue(Name = "DoSynchronize")]
		public bool DoSynchronize {
			get { return _DoSynchronize; }
			set {
				if (_DoSynchronize == value) {
					return;
				}
				_DoSynchronize = value;
				if (_DoSynchronize) {
					_running = true;
					createThread();
				}
				else {
					_running = false;
					m_are.Set();
				}
			}
		}

		#endregion

		#region Private Fields

		private readonly AutoResetEvent m_are = new AutoResetEvent(false);
		private bool _DoSynchronize = true;
		private bool _running = true;
		private Image<Bgr, byte> m_img;
		private ICaptureSource m_src;
		private Thread m_tQueryier;

		#endregion

		#region Public Methods

		public NextImageProvider() {
			createThread();
			ImageProviderId = "NextImageProvider.ImageData";
		}

		#endregion

		#region Private Methods

		private void createThread() {
			m_tQueryier = new Thread(QueryFrames);
			m_tQueryier.Start();
		}

		protected override Image<Bgr, byte> Convert(ICaptureSource toProcess) {
			m_src = toProcess;
			if (CurrentCaptureSourceInformationProviderService != null) {
				CurrentCaptureSourceInformationProviderService.SetCurrentCaptureSource(toProcess);
			}


			if (!DoSynchronize) {
				Image<Bgr, byte> img = m_src.QueryImage();
				if (ForwardImageToImageProvider) {
					ImageProviderService.SetImage(ImageProviderId, img.Clone().Convert<Lab, Byte>());
				}
				if (CurrentImageInformationProviderService != null) {
					CurrentImageInformationProviderService.SetImageSize(new Size(img.Width, img.Height));
				}
				if (ImageValidRegionProvider != null) {
					ImageValidRegionProvider.ResetInvalidRegionData();
				}
				return img;
			}

			m_are.WaitOne();
			if (ForwardImageToImageProvider) {
				ImageProviderService.SetImage(ImageProviderId, m_img.Clone().Convert<Lab, Byte>());
			}
			if (CurrentImageInformationProviderService != null) {
				CurrentImageInformationProviderService.SetImageSize(new Size(m_img.Width, m_img.Height));
			}
			if (ImageValidRegionProvider != null) {
				ImageValidRegionProvider.ResetInvalidRegionData();
			}
			return m_img.Clone();
		}

		private void QueryFrames() {
			while (_running) {
				if (m_src != null) {
					Image<Bgr, byte> toReturn = m_src.QueryImage();
					m_img = toReturn;
					m_are.Set();
				}

				Thread.Sleep(42);
			}
		}

		#endregion
	}
}